package org.tacticalTroopers.jme.server.object;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.vecmath.Matrix3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.tacticalTroopers.jme.common.message.Element;
import org.tacticalTroopers.jme.common.message.Id;
import org.tacticalTroopers.jme.server.DelayedGameAction;
import org.tacticalTroopers.jme.server.GameAction;

import com.bulletphysics.linearmath.Transform;

public class ServerElement {
	Log log = LogFactory.getLog(getClass());

	final Transform trans = new Transform();
	Vector3f size = new Vector3f();
	Float mass = 0f;
	Boolean updatedByUser = false;
	//List<ServerElement> collidees = new ArrayList<ServerElement>();
	Map<Class<? extends ServerElement>,List<ServerElement>> collidees = new HashMap<Class<? extends ServerElement>,List<ServerElement>>();
	Element element;
	
	Map<String,Object> attributes = new HashMap<String,Object>();
	

	public ServerElement(){
		element = new Element();
		setRotation(0f, 0f,0f);
		element.setType(Element.ELEMENT);
	}


	public void setId(Id id) {
		element.setId(id);
	}

	public Id getId() {
		return element.getId();
	}

	public void setMass(Float mass) {
		this.mass = mass;		
	}

	public Float getMass() {
		return mass;
	}


	Quat4f tmpQuat = new Quat4f();
	public void setTransform(Transform tmpTrans) {
		trans.set(tmpTrans);
		trans.getRotation(tmpQuat);
		//log.info("display rot: "+tmpQuat);
		element.setRotation(tmpQuat.x, tmpQuat.y, tmpQuat.z,tmpQuat.w);
		element.setPosition(trans.origin.x,trans.origin.y,trans.origin.z);
	}

	public final Transform getTransform() {
		return trans;
	}

	public Element getElementMessage() {
		return element;
	}


	public ServerElement setSize(float f, float g, float h) {
		size.set(f, g, h);
		element.setSize(f, g, h);
		return this;
	}


	public void addCollidee(ServerElement elem){
		List<ServerElement> list = collidees.get(elem.getClass());
		if(list==null){
			list=new ArrayList<ServerElement>();
			collidees.put(elem.getClass(),list);
		}
		list.add(elem);
	}

	public void clearCollidees(){
		for(List<ServerElement> list : collidees.values()){
			list.clear();
		}
	}

	public Map<Class<? extends ServerElement>,List<ServerElement>> getCollidees() {
		return collidees;
	}

	public Vector3f getSize() {
		return size;
	}

	public Vector3f getPosition() {
		return trans.origin;
	}



	public Matrix3f getOriantation() {
		return trans.basis;
	}

	public void setOriantation(Matrix3f oriantation) {
		trans.set(oriantation);
		updatedByUser = true;
		Quat4f res = new Quat4f();
		trans.getRotation(res);
		element.setRotation(res.x,res.y, res.z,res.w);
		//oriantation.g
		
	}


	public ServerElement setPosition(Float f, Float g, Float h) {
		trans.origin.set(f, g, h );
		element.setPosition(f, g, h);
		updatedByUser = true;
		return this;
	}

	public ServerElement setPosition(Vector3f position){
		trans.origin.set(position);
		element.setPosition(position);
		updatedByUser = true;
		return this;
	}



	public ServerElement setRotation(Float rotX,Float rotY,Float rotZ){
		trans.basis.rotX(rotX);
		trans.basis.rotY(rotY);
		trans.basis.rotZ(rotZ);
		//element.setRotation(rotX*FastMath.PI/180,rotY*FastMath.PI/180,rotZ*FastMath.PI/180,1f);
		element.setRotation(rotX,rotY,rotZ);


		return this;
	}

	List<GameAction> actions = new ArrayList<GameAction>();
	List<GameAction> actionsToRemove = new ArrayList<GameAction>();
	List<GameAction> actionsToAdd = new ArrayList<GameAction>();

	public void addAction(GameAction gameAction) {
		actionsToAdd.add(gameAction);
	}
	
	public void step(Integer milliseconds){
		
		for(GameAction gameAction : actions){
			//gameAction.setStepDuration(milliseconds);
			gameAction.action(this,milliseconds);
		}
		actions.addAll(actionsToAdd);
		actions.removeAll(actionsToRemove);
		actionsToAdd.clear();
		actionsToRemove.clear();
	}

	public void removeAction(GameAction gameAction) {
		actionsToRemove.add(gameAction);
		
	}
	
	public Boolean isUpdatedByUser(){
		return updatedByUser;
	}
	
	public void resetUpdatedByUser(){
		updatedByUser = false;
	}
	
	public ServerElement setAttribute(String key,Boolean bool) {
		attributes.put(key.intern(), bool);
		return this;
	}
	
	public ServerElement setAttribute(String key,String value) {
		attributes.put(key.intern(), value);
		return this;
	}
	
	public Boolean getAttributeBoolean(String key,Boolean defaultValue){
		Boolean b = (Boolean)attributes.get(key.intern());
		return b==null?defaultValue:b;
	}
	
	public String getAttributeString(String key){
		return (String)attributes.get(key.intern());
	}
	
	@Override
	public String toString() {
		return element.toString();
	}
	
}
